home *** CD-ROM | disk | FTP | other *** search
- /*
- ** Eject - AmigaDOS 2.04 utility
- **
- ** Copyright © 1994-1994 by Olaf `Olsen' Barthel
- ** Public Domain
- **
- ** :ts=4
- */
-
- /* Just a few includes... */
-
- #include <intuition/intuitionbase.h>
-
- #include <exec/execbase.h>
- #include <exec/memory.h>
- #include <exec/io.h>
-
- #include <devices/scsidisk.h>
-
- #include <workbench/workbench.h>
- #include <workbench/startup.h>
-
- #include <dos/filehandler.h>
- #include <dos/dosextens.h>
- #include <dos/rdargs.h>
-
- #include <clib/intuition_protos.h>
- #include <clib/exec_protos.h>
- #include <clib/icon_protos.h>
- #include <clib/dos_protos.h>
- #include <clib/wb_protos.h>
-
- #include <string.h>
-
- /* SCSI start/stop unit command. */
-
- struct StartStopUnit
- {
- UBYTE OperationCode, /* 0x1B */
- LUN_Reserved_Immed, /* %AAABBBBC, A = LUN, C = Immediate (0 = wait for completion) */
- Reserved[2],
- LoEj_Start, /* %000000AB, A = Load/Eject (1 = eject after stop), */
- Control; /* B = Start/Stop (1 = Start, 0 = Stop) */
- };
-
- /* SCSI test unit ready command. */
-
- struct TestUnitReady
- {
- UBYTE Command, /* 0x00 */
- LUN,
- Reserved[3],
- Control;
- };
-
- /* SCSI inquiry command. */
-
- struct Inquiry
- {
- UBYTE Command, /* 0x12 */
- LUN,
- PageCode,
- Reserved,
- AllocationLength,
- Control;
- };
-
- /* Data format returned by inquiry command. */
-
- struct InquiryData
- {
- UBYTE PeripheralType,
- DeviceTypeModifier,
- Version,
- Reserved[5],
- Vendor[8],
- Product[16],
- Revision[4];
- };
-
- /* Version identification. */
-
- STRPTR Version = "$VER: Eject 1.0 (25.12.94)\r\n";
-
- /* Global library bases. */
-
- struct ExecBase *SysBase;
- struct DosLibrary *DOSBase;
- struct IntuitionBase *IntuitionBase;
- struct Library *IconBase,
- *WorkbenchBase;
-
- /* Shell command template data. */
-
- STRPTR Template = "DEVICE/A/M";
-
- enum { ARG_DEVICE=0, ARGCOUNT };
-
- /* Prototypes for this module. */
-
- BYTE DoSCSICmd(struct IOStdReq *DeviceRequest,ULONG Unit,APTR Command,LONG CommandLen,APTR Data,LONG DataLen);
- BYTE TestUnitReady(struct IOStdReq *DeviceRequest,ULONG Unit);
- BOOL CheckMediaType(struct IOStdReq *DeviceRequest,ULONG Unit);
- BYTE EjectMedia(struct IOStdReq *DeviceRequest,ULONG Unit);
- BOOL Eject(const STRPTR DeviceName,ULONG Unit,ULONG Flags,BOOL Echo);
- BOOL FindDevice(const BPTR FileLock,const STRPTR FileName,STRPTR Device,ULONG *Unit,ULONG *Flags);
-
- /* Main(VOID):
- *
- * Program entry point.
- */
-
- LONG __saveds
- Main(VOID)
- {
- struct Process *ThisProcess;
- LONG Result = RETURN_FAIL;
- struct WBStartup *WBenchMsg;
-
- /* Set up SysBase. */
-
- SysBase = *(struct ExecBase **)4;
-
- /* That's me. */
-
- ThisProcess = (struct Process *)FindTask(NULL);
-
- /* Are we a child of Workbench? */
-
- if(ThisProcess -> pr_CLI)
- WBenchMsg = NULL;
- else
- {
- /* Wait for the startup message. */
-
- WaitPort(&ThisProcess -> pr_MsgPort);
-
- WBenchMsg = (struct WBStartup *)GetMsg(&ThisProcess -> pr_MsgPort);
- }
-
- /* Open dos.library. */
-
- if(DOSBase = (struct DosLibrary *)OpenLibrary("dos.library",37))
- {
- /* Workbench invocation? */
-
- if(WBenchMsg)
- {
- struct MsgPort *IconPort;
-
- /* Hold it... */
-
- Forbid();
-
- /* See if Eject is already running, if so tell
- * it to quit.
- */
-
- if(IconPort = FindPort("« Eject »"))
- Signal(IconPort -> mp_SigTask,SIGBREAKF_CTRL_C);
-
- Permit();
-
- /* Are we the one and only ?*/
-
- if(!IconPort)
- {
- /* Create the global port. */
-
- if(IconPort = CreateMsgPort())
- {
- /* Give it a name and a special priority. */
-
- IconPort -> mp_Node . ln_Name = "« Eject »";
- IconPort -> mp_Node . ln_Pri = 1;
-
- /* Open Intuition if possible. */
-
- IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",37);
-
- /* Take care of the remaining libraries. */
-
- if(IconBase = OpenLibrary("icon.library",37))
- {
- if(WorkbenchBase = OpenLibrary("workbench.library",37))
- {
- BPTR OldDir = CurrentDir(WBenchMsg -> sm_ArgList -> wa_Lock);
- struct DiskObject *Icon = GetDiskObjectNew(WBenchMsg -> sm_ArgList -> wa_Name);
-
- /* We need the icon. */
-
- if(Icon)
- {
- struct AppIcon *AppIcon;
-
- /* Add the AppIcon. */
-
- if(AppIcon = AddAppIconA(0,0,FilePart(WBenchMsg -> sm_ArgList -> wa_Name),IconPort,NULL,Icon,NULL))
- {
- struct AppMessage *Message;
- ULONG Signals;
- BOOL Done = FALSE;
- struct Window *ReqWindow = NULL;
- struct AppWindow *AppWindow = NULL;
-
- /* Make the global port visible. */
-
- AddPort(IconPort);
-
- /* Keep going... */
-
- do
- {
- /* Tie in the window signal if necessary. */
-
- if(ReqWindow)
- Signals = 1L << ReqWindow -> UserPort -> mp_SigBit;
- else
- Signals = NULL;
-
- /* Wait for something to happen. */
-
- Signals = Wait(Signals | (1L << IconPort -> mp_SigBit) | SIGBREAKF_CTRL_C);
-
- /* Do we have the notification window open? */
-
- if(ReqWindow)
- {
- /* Did the signal originate here? */
-
- if(Signals & (1L << ReqWindow -> UserPort -> mp_SigBit))
- {
- ULONG IDCMP = NULL;
- LONG Result;
-
- /* Process the events. */
-
- Result = SysReqHandler(ReqWindow,&IDCMP,FALSE);
-
- /* Shut the window? */
-
- if(Result == 0 || (Result == -2 && !(IDCMP & IDCMP_RAWKEY)))
- {
- if(AppWindow)
- {
- RemoveAppWindow(AppWindow);
-
- AppWindow = NULL;
- }
-
- FreeSysRequest(ReqWindow);
-
- ReqWindow = NULL;
- }
- }
- }
-
- /* A signal from Workbench? */
-
- if(Signals & (1L << IconPort -> mp_SigBit))
- {
- /* Pick up all incoming data. */
-
- while(Message = (struct AppMessage *)GetMsg(IconPort))
- {
- /* User dropped icons on the AppWindow/AppIcon. */
-
- if(Message -> am_NumArgs)
- {
- UBYTE DeviceName[256];
- ULONG Unit,Flags;
- LONG i;
-
- /* Take care of all entries. */
-
- for(i = 0 ; i < Message -> am_NumArgs ; i++)
- {
- if(FindDevice(Message -> am_ArgList[i] . wa_Lock,Message -> am_ArgList[i] . wa_Name,DeviceName,&Unit,&Flags))
- Eject(DeviceName,Unit,Flags,FALSE);
- }
- }
- else
- {
- /* It's just a double-click on the icon.
- * See if the notification window is
- * already open.
- */
-
- if(ReqWindow)
- {
- /* Make the window visible. */
-
- if(IntuitionBase -> LibNode . lib_Version >= 39)
- ScreenPosition(ReqWindow -> WScreen,SPOS_MAKEVISIBLE,ReqWindow -> LeftEdge,ReqWindow -> TopEdge,ReqWindow -> LeftEdge + ReqWindow -> Width - 1,ReqWindow -> TopEdge + ReqWindow -> Height - 1);
-
- WindowToFront(ReqWindow);
-
- ScreenToFront(ReqWindow -> WScreen);
-
- ActivateWindow(ReqWindow);
- }
- else
- {
- /* Did we succeed in opening Intuition? */
-
- if(IntuitionBase)
- {
- struct EasyStruct Easy;
-
- /* Fill in the data. */
-
- Easy . es_StructSize = sizeof(struct EasyStruct);
- Easy . es_Flags = NULL;
- Easy . es_Title = (STRPTR)"Eject";
- Easy . es_GadgetFormat = (STRPTR)"Continue";
- Easy . es_TextFormat = (STRPTR)"\"Eject\" Copyright © 1994-1995 by\nOlaf `Olsen' Barthel <olsen@sourcery.han.de>\nPublic Domain";
-
- /* Open the notification window and just
- * for the fun of it make it an AppWindow.
- */
-
- if(ReqWindow = BuildEasyRequest(NULL,&Easy,IDCMP_RAWKEY,NULL))
- AppWindow = AddAppWindowA(0,0,ReqWindow,IconPort,NULL);
- }
- }
- }
-
- ReplyMsg((struct Message *)Message);
- }
- }
-
- /* Terminate? */
-
- if(Signals & SIGBREAKF_CTRL_C)
- Done = TRUE;
- }
- while(!Done);
-
- /* Remove the AppWindow link. */
-
- if(AppWindow)
- RemoveAppWindow(AppWindow);
-
- /* Remove the AppIcon. */
-
- RemoveAppIcon(AppIcon);
-
- /* Hide the global port. */
-
- RemPort(IconPort);
-
- /* Dispatch all remaining messages. */
-
- while(Message = (struct AppMessage *)GetMsg(IconPort))
- ReplyMsg((struct Message *)Message);
-
- /* Close the notification window if necessary. */
-
- if(ReqWindow)
- FreeSysRequest(ReqWindow);
- }
-
- /* Get rid of the icon. */
-
- FreeDiskObject(Icon);
- }
-
- /* Get back... */
-
- CurrentDir(OldDir);
-
- /* And clean up the libraries. */
-
- CloseLibrary(WorkbenchBase);
- }
-
- CloseLibrary(IconBase);
- }
-
- if(IntuitionBase)
- CloseLibrary((struct Library *)IntuitionBase);
-
- /* Don't forget the global port. */
-
- DeleteMsgPort(IconPort);
- }
- }
- }
- else
- {
- struct RDArgs *ArgsPtr;
- STRPTR Args[ARGCOUNT];
-
- /* Clear the args. */
-
- memset(Args,0,sizeof(Args));
-
- /* Read the command arguments if any. */
-
- if(ArgsPtr = ReadArgs(Template,(LONG *)Args,NULL))
- {
- STRPTR *Names = (STRPTR *)Args[ARG_DEVICE];
-
- /* Process all names. */
-
- while(*Names)
- {
- UBYTE DeviceName[256];
- ULONG Unit,Flags;
- BPTR FileLock;
-
- /* Try to get a lock on the object in question. */
-
- FileLock = Lock(*Names,ACCESS_READ);
-
- /* Try to find the corresponding device. */
-
- if(FindDevice(FileLock,*Names,DeviceName,&Unit,&Flags))
- {
- /* Don't keep the icon longer on the
- * desktop than necessary.
- */
-
- UnLock(FileLock);
-
- /* Try to eject the media. */
-
- if(Eject(DeviceName,Unit,Flags,TRUE))
- Result = RETURN_OK;
- else
- {
- if(Result == RETURN_FAIL)
- Result = RETURN_ERROR;
- else
- Result = RETURN_WARN;
- }
- }
- else
- {
- /* Release the file lock. */
-
- UnLock(FileLock);
-
- Printf("Eject: Unable to find device \"%s\".\n",*Names);
-
- if(Result == RETURN_FAIL)
- Result = RETURN_ERROR;
- else
- Result = RETURN_WARN;
- }
-
- /* Proceed to the next name... */
-
- Names++;
- }
- }
- else
- {
- PrintFault(IoErr(),"Eject");
-
- Result = RETURN_ERROR;
- }
- }
-
- /* Clean up. */
-
- CloseLibrary((struct Library *)DOSBase);
- }
- else
- ThisProcess -> pr_Result2 = ERROR_INVALID_RESIDENT_LIBRARY;
-
- /* Reply the startup message if necessary. */
-
- if(WBenchMsg)
- {
- Forbid();
-
- ReplyMsg((struct Message *)WBenchMsg);
- }
-
- return(Result);
- }
-
- /* DoSCSICmd(...):
- *
- * Send a SCSI command to the driver in question.
- */
-
- BYTE
- DoSCSICmd(struct IOStdReq *DeviceRequest,ULONG Unit,APTR Command,LONG CommandLen,APTR Data,LONG DataLen)
- {
- struct SCSICmd SCSICmd;
- UBYTE *CommandArray = Command,
- SenseBuffer[20];
-
- /* Patch in the LUN. */
-
- CommandArray[1] |= ((Unit / 10) & 7) << 5;
-
- /* Set up the basic data. */
-
- DeviceRequest -> io_Command = HD_SCSICMD;
- DeviceRequest -> io_Data = &SCSICmd;
- DeviceRequest -> io_Length = sizeof(struct SCSICmd);
-
- /* Now fill in the command. */
-
- memset(&SCSICmd,0,sizeof(struct SCSICmd));
-
- SCSICmd . scsi_Command = Command;
- SCSICmd . scsi_CmdLength = CommandLen;
- SCSICmd . scsi_Flags = SCSIF_AUTOSENSE;
- SCSICmd . scsi_SenseData = SenseBuffer;
- SCSICmd . scsi_SenseLength = 18;
-
- if(Data)
- {
- SCSICmd . scsi_Data = Data;
- SCSICmd . scsi_Length = DataLen;
-
- SCSICmd . scsi_Flags |= SCSIF_READ;
- }
- else
- SCSICmd . scsi_Flags |= SCSIF_WRITE;
-
- /* Cast the dice. */
-
- return(DoIO((struct IORequest *)DeviceRequest));
- }
-
- /* TestUnitReady(struct IOStdReq *DeviceRequest,ULONG Unit):
- *
- * Check if this particular device is ready for action,
- * i.e. there is a medium loaded.
- */
-
- BYTE
- TestUnitReady(struct IOStdReq *DeviceRequest,ULONG Unit)
- {
- struct TestUnitReady TestUnitReady;
-
- memset(&TestUnitReady,0,sizeof(TestUnitReady));
-
- return(DoSCSICmd(DeviceRequest,Unit,&TestUnitReady,sizeof(TestUnitReady),NULL,0));
- }
-
- /* CheckMediaType(struct IOStdReq *DeviceRequest,ULONG Unit):
- *
- * Check if the device in question supports removable
- * media. However, this does not mean that the device is
- * capable of ejecting it on its own.
- */
-
- BOOL
- CheckMediaType(struct IOStdReq *DeviceRequest,ULONG Unit)
- {
- struct Inquiry Inquiry;
- struct InquiryData InquiryData;
-
- memset(&Inquiry,0,sizeof(Inquiry));
-
- Inquiry . Command = 0x12;
- Inquiry . AllocationLength = sizeof(struct InquiryData);
-
- if(!DoSCSICmd(DeviceRequest,Unit,&Inquiry,sizeof(struct Inquiry),&InquiryData,sizeof(struct InquiryData)))
- {
- /* A removable medium bit of zero indicates that the
- * medium is not removable. A RMB bit of one indicates
- * that the medium is removable.
- */
-
- if(InquiryData . DeviceTypeModifier & 0x80)
- return(TRUE);
- }
-
- return(FALSE);
- }
-
- /* EjectMedia(struct IOStdReq *DeviceRequest,ULONG Unit):
- *
- * Eject the removable medium; this is accomplished via
- * the start/stop command. We request that the medium
- * should be unloaded after the unit is stopped. This
- * command is sometimes referred to as "load unload".
- */
-
- BYTE
- EjectMedia(struct IOStdReq *DeviceRequest,ULONG Unit)
- {
- struct StartStopUnit StartStopUnit;
-
- memset(&StartStopUnit,0,sizeof(StartStopUnit));
-
- StartStopUnit . OperationCode = 0x1B;
- StartStopUnit . LoEj_Start = 0x02;
-
- return(DoSCSICmd(DeviceRequest,Unit,&StartStopUnit,sizeof(StartStopUnit),NULL,0));
- }
-
- /* Eject(const STRPTR DeviceName,ULONG Unit,ULONG Flags,BOOL Echo):
- *
- * This routine does the dirty work. Open the device driver,
- * check for the device type, see if any media is loaded,
- * eject it if necessary.
- */
-
- BOOL
- Eject(const STRPTR DeviceName,ULONG Unit,ULONG Flags,BOOL Echo)
- {
- struct MsgPort *DevicePort;
- BOOL Result = FALSE;
-
- /* Set up the interface data... */
-
- if(DevicePort = CreateMsgPort())
- {
- struct IOStdReq *DeviceRequest;
-
- if(DeviceRequest = (struct IOStdReq *)CreateIORequest(DevicePort,sizeof(struct IOStdReq)))
- {
- if(!OpenDevice(DeviceName,Unit,(struct IORequest *)DeviceRequest,Flags))
- {
- Result = TRUE;
-
- /* So far, so good. Now take a look if the device
- * supports removable media.
- */
-
- if(CheckMediaType(DeviceRequest,Unit))
- {
- /* Now check if there is any media loaded.
- * We do the check twice in case the medium
- * has just been loaded. To indicate this
- * case, the SCSI standard requests that the
- * device rejects the first command following
- * the medium change.
- */
-
- if(!TestUnitReady(DeviceRequest,Unit) && !TestUnitReady(DeviceRequest,Unit))
- {
- /* Go! */
-
- if(EjectMedia(DeviceRequest,Unit))
- {
- if(Echo)
- Printf("Eject: Error #%ld ejecting media.\n",DeviceRequest -> io_Error);
-
- Result = FALSE;
- }
- }
- }
-
- /* Clean up... */
-
- CloseDevice((struct IORequest *)DeviceRequest);
- }
- else
- {
- if(Echo)
- Printf("Eject: Error #%ld opening device \"%s\" unit #%ld.\n",DeviceRequest -> io_Error,DeviceName,Unit);
- }
-
- DeleteIORequest(DeviceRequest);
- }
- else
- {
- if(Echo)
- Printf("Eject: Cannot create IOStdReq.\n");
- }
-
- DeleteMsgPort(DevicePort);
- }
- else
- {
- if(Echo)
- Printf("Eject: Cannot create MsgPort.\n");
- }
-
- return(Result);
- }
-
- /* FindDevice(...):
- *
- * Find a device by name/filelock.
- */
-
- BOOL
- FindDevice(const BPTR FileLock,const STRPTR FileName,STRPTR Device,ULONG *Unit,ULONG *Flags)
- {
- struct DosList *Entry;
-
- /* For a start, lock the doslist entries we are interested in. */
-
- if(Entry = LockDosList(LDF_DEVICES | LDF_READ))
- {
- /* Do we have a filelock? */
-
- if(FileLock)
- {
- struct FileLock *LockPtr = (struct FileLock *)BADDR(FileLock);
-
- /* Walk down the list. */
-
- while(Entry = NextDosEntry(Entry,LDF_DEVICES | LDF_READ))
- {
- /* If the filing system task that manages this
- * device equals the one the filelock originated
- * from chances are very high that this is the
- * one we were looking for. Please note that this
- * technique is not absolutely bullet-proof as in
- * theory it is possible to write a filing system
- * which manages multiple devices. The task address
- * might thus not necessarily point to the right
- * doslist entry.
- */
-
- if(Entry -> dol_Task == LockPtr -> fl_Task)
- {
- struct FileSysStartupMsg *Startup = (struct FileSysStartupMsg *)BADDR(Entry -> dol_misc . dol_handler . dol_Startup);
-
- /* Is this a valid entry? There might not be
- * a pointer to the FSSM stored here; the
- * Port-Handler for example uses this field
- * to tell references to SER:, PAR: and PRT:
- * apart.
- */
-
- if(TypeOfMem(Startup))
- {
- /* Is this a valid device name? */
-
- if(TypeOfMem(BADDR(Startup -> fssm_Device)))
- {
- STRPTR Name = BADDR(Startup -> fssm_Device);
-
- /* Fill in the necessary data. */
-
- strcpy(Device,Name + 1);
-
- *Unit = Startup -> fssm_Unit;
- *Flags = Startup -> fssm_Flags;
-
- /* Release the list. */
-
- UnLockDosList(LDF_DEVICES | LDF_READ);
-
- /* Success. */
-
- return(TRUE);
- }
- }
- }
- }
- }
- else
- {
- UBYTE LocalName[256];
- LONG Len;
-
- /* Make a copy of the file name. */
-
- strcpy(LocalName,FileName);
-
- Len = strlen(LocalName);
-
- /* Remove the colon; we expect plain device
- * names such as DF0, CD0 or HD0 here.
- */
-
- if(LocalName[Len - 1] == ':')
- LocalName[Len - 1] = 0;
-
- /* Try to find the device entry in question. */
-
- if(Entry = FindDosEntry(Entry,LocalName,LDF_DEVICES | LDF_READ))
- {
- struct FileSysStartupMsg *Startup = (struct FileSysStartupMsg *)BADDR(Entry -> dol_misc . dol_handler . dol_Startup);
-
- if(TypeOfMem(Startup))
- {
- if(TypeOfMem(BADDR(Startup -> fssm_Device)))
- {
- STRPTR Name = BADDR(Startup -> fssm_Device);
-
- strcpy(Device,Name + 1);
-
- *Unit = Startup -> fssm_Unit;
- *Flags = Startup -> fssm_Flags;
-
- UnLockDosList(LDF_DEVICES | LDF_READ);
-
- return(TRUE);
- }
- }
- }
- }
-
- UnLockDosList(LDF_DEVICES | LDF_READ);
- }
-
- return(FALSE);
- }
-